package UIUtils
{
	
	import MLP.mlp_effectLayer;
	
	import UIFree.uif_loader;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.BitmapDataChannel;
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.display.PixelSnapping;
	import flash.events.Event;
	import flash.geom.Matrix3D;
	import flash.geom.Rectangle;
	import flash.utils.ByteArray;
	
	import ru.inspirit.net.JPGFileUploader;

	public class uif_MLPEncoder {
		public static const HEADER: String = 'MLP.V 0.2';
		
		private static const TYPEBLOCKBITMAP	: int = 1;
		private static const TYPEBLOCKEFFECT	: int = 2;
		private static const TYPEBLOCKEXT		: int = 1000;
		public static const TYPEBLOCKURL		: int = 1001;
		
		public static function encode(elems: DisplayObjectContainer, extList: Array=null): ByteArray {
			var je		: JPGEncoder = new JPGEncoder(80);
			var result	: ByteArray = new ByteArray();
			var a		: Array = new Array();
			var pos		: uint = 0;
			
			result.writeUTF(HEADER);
			result.writeInt(elems.numChildren + (extList?extList.length:0));
			
			for (var i: int = 0; i<elems.numChildren; i++) {
				
				var child	: DisplayObject = elems.getChildAt(i);
				var bmd		: BitmapData;
				var image	: ByteArray = null;
				var alpha	: ByteArray = null;
				var m		: Matrix3D = child.transform.matrix3D;
				var type	: uint;
				
				if (child is Bitmap) {
					type	= TYPEBLOCKBITMAP;
					bmd 	= (child as Bitmap).bitmapData;
					var alphaBmd: BitmapData = new BitmapData(bmd.width, bmd.height, false, 0);
					alphaBmd.copyChannel(bmd, bmd.rect, uif_util.NULLPOINT, BitmapDataChannel.ALPHA, BitmapDataChannel.RED);
					image 	= je.encode(bmd);
					alpha 	= je.encode(alphaBmd);
				} else if (child is mlp_effectLayer) {
					type	= TYPEBLOCKEFFECT;
					image	= new ByteArray();
					alpha	= new ByteArray();
					var a_effect: mlp_effectLayer = child as mlp_effectLayer;
					image.writeObject({
						params	: a_effect.params,
						size	: {
							x: a_effect.width,
							y: a_effect.height
						}
					});
				}

				result.writeInt(type);
				result.writeInt(pos);
				result.writeInt(image.length);
				result.writeInt(alpha.length);
				for (var n: int=0; n<m.rawData.length; n++) result.writeFloat(m.rawData[n]);
				
				pos += image.length;
				pos += alpha.length;
				a.push({
					i: image,
					a: alpha
				});
			}
			
			if (extList) extList.forEach(function(ext: Object, i: int, arr: Array): void {
				result.writeInt(ext.type);
				result.writeInt(pos);
				if (ext.data is String) {
					var bad: ByteArray = new ByteArray();
					bad.writeUTF(ext.data as String);
					ext.data 	= bad;
					ext.length 	= bad.length;
				}
				result.writeInt(ext.length);
				result.writeInt(0);
				pos += ext.length;
				a.push({
					i: ext.data
				});
			});
			
			a.forEach(function(info: Object, i: int, arr: Array): void {
				if (info.i.length > 0) result.writeBytes(info.i);
				if (info.a && (info.a.length > 0)) result.writeBytes(info.a);
			});
			
			return result;
		}
		
		public static function decode(elems: ByteArray, doComplete: Function): void {
			var result	: Array = new Array();
			var a		: Array = new Array();
			elems.position = 0;
			var header: String = elems.readUTF();
			if (header == HEADER) {
				var count: int = elems.readInt();
				for (var i: int=0; i<count; i++) {
					var info: Object = {
						type	: elems.readInt(),
						position: elems.readInt(),
						imageLen: elems.readInt(),	
						alphaLen: elems.readInt()	
					}
					if (info.type < TYPEBLOCKEXT) {
						var v: Vector.<Number> = new Vector.<Number>(16);
						for (var n: int=0; n<v.length; n++) v[n] = elems.readFloat();
						info.matrix = new Matrix3D(v);
					}
					a.push(info);
				}
			}
			
			var startPos: int = elems.position;
			
			a.forEach(function(info: Object, i: int, arr: Array): void {
				function doCompleteBmd(loaderImage: Loader, loaderAlpha: Loader): void {
					
					var image: BitmapData = uif_utilBitmap.copyBitmapData(loaderImage);
					var alpha: BitmapData = uif_utilBitmap.copyBitmapData(loaderAlpha);
					image.copyChannel(alpha, alpha.rect, uif_util.NULLPOINT, BitmapDataChannel.RED, BitmapDataChannel.ALPHA);
					var bmp: Bitmap = new Bitmap(image, PixelSnapping.AUTO, true);
					bmp.transform.matrix3D = info.matrix;
					result.push(bmp);
					if (result.length == count) doComplete(result);
				}
				
				function doLoadLoader(e: Event): void {
					if ((loaderAlpha.contentLoaderInfo.bytesTotal == loaderAlpha.contentLoaderInfo.bytesLoaded) && 
						(loaderImage.contentLoaderInfo.bytesTotal == loaderImage.contentLoaderInfo.bytesLoaded)) {
						loaderAlpha.contentLoaderInfo.removeEventListener(Event.COMPLETE, doLoadLoader);
						loaderImage.contentLoaderInfo.removeEventListener(Event.COMPLETE, doLoadLoader);
						doCompleteBmd(loaderImage, loaderAlpha);
						loaderImage.unload();
						loaderAlpha.unload();
					}
				}
				
				var image: ByteArray = new ByteArray();
				var alpha: ByteArray = new ByteArray();
				if (info.imageLen > 0) elems.readBytes(image, 0, info.imageLen);
				if (info.alphaLen > 0) elems.readBytes(alpha, 0, info.alphaLen);
				
				if (info.type == TYPEBLOCKBITMAP) {
					var loaderImage: Loader = new Loader();
					loaderImage.contentLoaderInfo.addEventListener(Event.COMPLETE, doLoadLoader);
					loaderImage.loadBytes(image);
					var loaderAlpha: Loader = new Loader();
					loaderAlpha.contentLoaderInfo.addEventListener(Event.COMPLETE, doLoadLoader);
					loaderAlpha.loadBytes(alpha);
				} else if (info.type == TYPEBLOCKEFFECT) {
					var infoEffect: Object = image.readObject();
					var effect: mlp_effectLayer = new mlp_effectLayer(infoEffect.params);
					effect.width = infoEffect.size.x;
					effect.height = infoEffect.size.y;
					effect.transform.matrix3D = info.matrix;
					effect.load(function(_effectInterface: Object): void {
						result.push(effect);
						if (result.length == count) doComplete(result);
					});
				} else if (info.type > TYPEBLOCKEXT) {
					result.push(info);
					result.data = image;
					if (result.length == count) doComplete(result);
				}
			});
		}
	}
}